How to update nested sub-documents in Mongo DB
Updating sub-documents in NoSQL Mongo DB is bit trickey, so here we have come up with an solution how to update level 1 and level 2 nested subdocuments.
Lets Consider below document as example:
{
id: 1,
forecasts: [ {
forecast_id: 123,
name: "Forecast 1",
levels: [
{
levelid:1221
levelname: "proven",
configs: [
{
config: "Custom 1",
variables: [{ x: 1, y:2, z:3}]
},
{
config: "Custom 2",
variables: [{ x: 10, y:20, z:30}]
},
]
},
{
levelid:1221
levelname: "likely",
configs: [
{
config: "Custom 1",
variables: [{ x: 1, y:2, z:3}]
},
{
config: "Custom 2",
variables: [{ x: 10, y:20, z:30}]
},
]
}
]
},
]
}
For the above document level, 1 update operation looks like below. Here we are updating forecast’s first id name from “Forecast 1” to “New Forecast 1” for this one updateOne finds works fine. as written in below code
db.weather.updateOne({
"id": ObjectId("1"),
"forecasts.forecast_id": ObjectId("123")
},
{ $set: { "forecasts.$.name": "New forecast 1" } }).then((result) => {
resolve(result);
}, (err) => {
reject(err);
});
For the above document level 2 update operation looks like below. Here we are updating forecasts first id levels levelid:1221 levelname from “proven” to “new proven”. Here to select and set second level subdocument we used Mongo DB arrayFilters and also $eleMatch
db.weather.updateOne({
"_id": ObjectId("1"), //this is level O select
"forecasts": {
"$elemMatch": {
"forecast_id": ObjectId("123"), //this is level one select
"levels.levelid": ObjectId("1221") // this is level to select
}
}
},
{
"$set": {
"forecasts.$[outer].levels.$[inner].levelname": "New proven",
}
},
{
"arrayFilters": [
{ "outer.forecast_id": ObjectId("123") },
{ "inner.levelid": ObjectId("1221") }
]
}).then((result) => {
resolve(result);
}, (err) => {
reject(err);
});
arrayFilter :In the update document, use the $[<identifier>] filtered positional operator to define an identifier, which you then reference in the array filter documents. You cannot have an array filter document for an identifier if the identifier is not included in the update document.
$eleMatch: The $elemMatch
operator limits the contents of an <array>
field from the query results to contain only the first element matching the $elemMatch
condition.
The $
operator projects the first matching array element from each document in a collection based on some condition from the query statement.
The $elemMatch
projection operator takes an explicit condition argument. This allows you to project based on a condition not in the query, or if you need to project based on multiple fields in the array’s embedded documents. See Array Field Limitations for an example.
If you have any Query about the methods used above, plesase comment down below and we will get back to you soon.
Arjun is a Full-stack developer, who is fond of the web. Lives in Chikmagalur, Karnataka, India